//! 身份认证模块
//! 
//! 这个模块负责JWT身份认证的实现，包括：
//! - JWT令牌生成和验证
//! - 用户认证服务
//! - 密码验证

use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};
use chrono::Utc;
use uuid::Uuid;

use crate::{
    config::JwtConfig,
    models::{User, UserRole, Claims, LoginResponse, UserInfo},
    database::DatabaseManager,
    errors::{AppError, AppResult},
};

/// JWT服务
/// 
/// 负责JWT令牌的生成、验证和管理
#[derive(Clone)]
pub struct JwtService {
    encoding_key: EncodingKey,
    decoding_key: DecodingKey,
    validation: Validation,
    config: JwtConfig,
}

impl JwtService {
    /// 创建新的JWT服务
    /// 
    /// # 参数
    /// - `config`: JWT配置
    /// 
    /// # 返回值
    /// - `Result<Self, AppError>`: 创建成功返回服务，失败返回错误
    pub fn new(config: &JwtConfig) -> AppResult<Self> {
        let encoding_key = EncodingKey::from_secret(config.secret.as_ref());
        let decoding_key = DecodingKey::from_secret(config.secret.as_ref());

        let mut validation = Validation::new(Algorithm::HS256);
        validation.set_issuer(&[config.issuer.clone()]);
        validation.set_audience(&[config.audience.clone()]);
        validation.set_required_spec_claims(&["exp", "iat", "sub"]);
        validation.leeway = 0; // 不允许时间偏差

        Ok(Self {
            encoding_key,
            decoding_key,
            validation,
            config: config.clone(),
        })
    }

    /// 生成JWT令牌
    /// 
    /// # 参数
    /// - `user`: 用户信息
    /// 
    /// # 返回值
    /// - `Result<String, AppError>`: 生成成功返回令牌字符串，失败返回错误
    pub fn generate_token(&self, user: &User) -> AppResult<String> {
        let now = Utc::now();
        let exp = now + chrono::Duration::days(self.config.expiration_days as i64);

        let claims = Claims {
            sub: user.id,
            username: user.username.clone(),
            email: user.email.clone(),
            role: user.role,
            iat: now.timestamp(),
            exp: exp.timestamp(),
            iss: self.config.issuer.clone(),
            aud: self.config.audience.clone(),
        };

        encode(&Header::default(), &claims, &self.encoding_key)
            .map_err(AppError::Jwt)
    }

    /// 验证JWT令牌
    /// 
    /// # 参数
    /// - `token`: JWT令牌字符串
    /// 
    /// # 返回值
    /// - `Result<Claims, AppError>`: 验证成功返回声明，失败返回错误
    pub fn verify_token(&self, token: &str) -> AppResult<Claims> {
        let token_data = decode::<Claims>(token, &self.decoding_key, &self.validation)
            .map_err(AppError::Jwt)?;

        Ok(token_data.claims)
    }

    /// 从令牌中提取用户ID
    /// 
    /// # 参数
    /// - `token`: JWT令牌字符串
    /// 
    /// # 返回值
    /// - `Result<Uuid, AppError>`: 提取成功返回用户ID，失败返回错误
    pub fn extract_user_id(&self, token: &str) -> AppResult<Uuid> {
        let claims = self.verify_token(token)?;
        Ok(claims.sub)
    }

    /// 刷新令牌
    /// 
    /// # 参数
    /// - `token`: 现有JWT令牌
    /// 
    /// # 返回值
    /// - `Result<String, AppError>`: 刷新成功返回新令牌，失败返回错误
    pub fn refresh_token(&self, token: &str) -> AppResult<String> {
        let claims = self.verify_token(token)?;
        
        // 创建新的声明，延长过期时间
        let now = Utc::now();
        let exp = now + chrono::Duration::days(self.config.expiration_days as i64);

        let new_claims = Claims {
            sub: claims.sub,
            username: claims.username,
            email: claims.email,
            role: claims.role,
            iat: now.timestamp(),
            exp: exp.timestamp(),
            iss: self.config.issuer.clone(),
            aud: self.config.audience.clone(),
        };

        encode(&Header::default(), &new_claims, &self.encoding_key)
            .map_err(AppError::Jwt)
    }
}

/// 认证服务
/// 
/// 提供完整的用户认证功能
#[derive(Clone)]
pub struct AuthService {
    jwt_service: JwtService,
    db: DatabaseManager,
}

impl AuthService {
    /// 创建新的认证服务
    /// 
    /// # 参数
    /// - `config`: JWT配置
    /// - `db`: 数据库管理器
    /// 
    /// # 返回值
    /// - `Self`: 认证服务实例
    pub fn new(config: &JwtConfig, db: DatabaseManager) -> Self {
        let jwt_service = JwtService::new(config).expect("Failed to create JWT service");
        
        Self {
            jwt_service,
            db,
        }
    }

    /// 用户登录
    /// 
    /// # 参数
    /// - `email_or_username`: 邮箱或用户名
    /// - `password`: 密码
    /// 
    /// # 返回值
    /// - `Result<LoginResponse, AppError>`: 登录成功返回登录响应，失败返回错误
    pub async fn login(&self, email_or_username: &str, password: &str) -> AppResult<LoginResponse> {
        tracing::info!("🔐 用户登录尝试: {}", email_or_username);

        // 查找用户
        let user = self.db.get_user_by_email_or_username(email_or_username)
            .await?
            .ok_or_else(|| {
                tracing::warn!("❌ 用户不存在: {}", email_or_username);
                AppError::validation("用户名或密码错误")
            })?;

        // 验证用户状态
        if user.status != crate::models::UserStatus::Active {
            tracing::warn!("❌ 用户账户未激活: {}", email_or_username);
            return Err(AppError::validation("账户未激活或已被禁用"));
        }

        // 验证密码
        if !self.db.verify_password(password, &user.password_hash)? {
            tracing::warn!("❌ 密码错误: {}", email_or_username);
            return Err(AppError::validation("用户名或密码错误"));
        }

        // 生成访问令牌
        let access_token = self.jwt_service.generate_token(&user)?;
        
        // 生成刷新令牌（这里简化处理，实际应用中应该单独管理刷新令牌）
        let refresh_token = self.jwt_service.generate_token(&user)?;

        // 更新最后登录时间
        self.db.update_last_login(user.id).await?;

        let response = LoginResponse {
            access_token,
            refresh_token,
            token_type: "Bearer".to_string(),
            expires_in: self.jwt_service.config.expiration_days * 24 * 60 * 60, // 转换为秒
            user: user.into(),
        };

        tracing::info!("✅ 用户登录成功: {}", response.user.username);
        Ok(response)
    }

    /// 验证令牌并获取用户信息
    /// 
    /// # 参数
    /// - `token`: JWT令牌
    /// 
    /// # 返回值
    /// - `Result<UserInfo, AppError>`: 验证成功返回用户信息，失败返回错误
    pub async fn verify_and_get_user(&self, token: &str) -> AppResult<UserInfo> {
        // 验证令牌
        let claims = self.jwt_service.verify_token(token)?;

        // 从数据库获取最新用户信息
        let user = self.db.get_user_by_id(claims.sub)
            .await?
            .ok_or(AppError::NotFound)?;

        // 检查用户状态
        if user.status != crate::models::UserStatus::Active {
            return Err(AppError::validation("账户已被禁用"));
        }

        Ok(user.into())
    }

    /// 刷新访问令牌
    /// 
    /// # 参数
    /// - `refresh_token`: 刷新令牌
    /// 
    /// # 返回值
    /// - `Result<String, AppError>`: 刷新成功返回新访问令牌，失败返回错误
    pub async fn refresh_access_token(&self, refresh_token: &str) -> AppResult<String> {
        // 验证刷新令牌
        let claims = self.jwt_service.verify_token(refresh_token)?;

        // 检查用户是否仍然存在且活跃
        let user = self.db.get_user_by_id(claims.sub)
            .await?
            .ok_or(AppError::NotFound)?;

        if user.status != crate::models::UserStatus::Active {
            return Err(AppError::validation("账户已被禁用"));
        }

        // 生成新的访问令牌
        let new_access_token = self.jwt_service.generate_token(&user)?;

        tracing::info!("✅ 令牌刷新成功: {}", user.username);
        Ok(new_access_token)
    }

    /// 验证令牌（不获取用户信息）
    /// 
    /// # 参数
    /// - `token`: JWT令牌
    /// 
    /// # 返回值
    /// - `Result<Claims, AppError>`: 验证成功返回声明，失败返回错误
    pub fn verify_token(&self, token: &str) -> AppResult<Claims> {
        self.jwt_service.verify_token(token)
    }

    /// 检查用户是否有指定权限
    /// 
    /// # 参数
    /// - `user_role`: 用户角色
    /// - `required_role`: 需要的角色
    /// 
    /// # 返回值
    /// - `bool`: 有权限返回true，无权限返回false
    pub fn has_permission(&self, user_role: UserRole, required_role: UserRole) -> bool {
        match (user_role, required_role) {
            (UserRole::SuperAdmin, _) => true,
            (UserRole::Admin, UserRole::User) => true,
            (UserRole::User, UserRole::User) => true,
            _ => false,
        }
    }

    /// 从Authorization头中提取令牌
    /// 
    /// # 参数
    /// - `auth_header`: Authorization头值
    /// 
    /// # 返回值
    /// - `Result<String, AppError>`: 提取成功返回令牌，失败返回错误
    pub fn extract_token_from_header(&self, auth_header: &str) -> AppResult<String> {
        if !auth_header.starts_with("Bearer ") {
            return Err(AppError::Unauthorized);
        }

        let token = &auth_header[7..]; // 移除 "Bearer " 前缀
        if token.is_empty() {
            return Err(AppError::Unauthorized);
        }

        Ok(token.to_string())
    }
}

/// 实现UserInfo的From trait
impl From<User> for UserInfo {
    fn from(user: User) -> Self {
        Self {
            id: user.id,
            username: user.username,
            email: user.email,
            full_name: user.full_name,
            avatar_url: user.avatar_url,
            status: user.status,
            role: user.role,
            created_at: user.created_at,
            updated_at: user.updated_at,
            last_login_at: user.last_login_at,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::models::UserStatus;

    fn create_test_user() -> User {
        User {
            id: Uuid::new_v4(),
            username: "test_user".to_string(),
            email: "test@example.com".to_string(),
            password_hash: "hashed_password".to_string(),
            full_name: Some("Test User".to_string()),
            avatar_url: None,
            status: UserStatus::Active,
            role: UserRole::User,
            created_at: Utc::now(),
            updated_at: Utc::now(),
            last_login_at: None,
        }
    }

    #[test]
    fn test_jwt_token_generation_and_verification() {
        let config = JwtConfig::default();
        let jwt_service = JwtService::new(&config).unwrap();
        let user = create_test_user();

        // 生成令牌
        let token = jwt_service.generate_token(&user).unwrap();
        assert!(!token.is_empty());

        // 验证令牌
        let claims = jwt_service.verify_token(&token).unwrap();
        assert_eq!(claims.sub, user.id);
        assert_eq!(claims.username, user.username);
        assert_eq!(claims.email, user.email);
        assert_eq!(claims.role, user.role);
    }

    #[test]
    fn test_token_extraction_from_header() {
        let config = JwtConfig::default();
        let auth_service = AuthService::new(&config, DatabaseManager {
            pool: todo!(), // 测试中需要模拟数据库
            config: Default::default(),
        });

        // 测试有效的Authorization头
        let valid_header = "Bearer valid_token_here";
        let token = auth_service.extract_token_from_header(valid_header).unwrap();
        assert_eq!(token, "valid_token_here");

        // 测试无效的Authorization头
        let invalid_header = "Invalid token";
        assert!(auth_service.extract_token_from_header(invalid_header).is_err());

        // 测试空的Authorization头
        let empty_header = "Bearer ";
        assert!(auth_service.extract_token_from_header(empty_header).is_err());
    }

    #[test]
    fn test_permission_checking() {
        let config = JwtConfig::default();
        let auth_service = AuthService::new(&config, DatabaseManager {
            pool: todo!(), // 测试中需要模拟数据库
            config: Default::default(),
        });

        // 测试超级管理员权限
        assert!(auth_service.has_permission(UserRole::SuperAdmin, UserRole::User));
        assert!(auth_service.has_permission(UserRole::SuperAdmin, UserRole::Admin));

        // 测试管理员权限
        assert!(auth_service.has_permission(UserRole::Admin, UserRole::User));
        assert!(!auth_service.has_permission(UserRole::Admin, UserRole::SuperAdmin));

        // 测试普通用户权限
        assert!(auth_service.has_permission(UserRole::User, UserRole::User));
        assert!(!auth_service.has_permission(UserRole::User, UserRole::Admin));
    }
}
